package com.whh.starter.utils;

import lombok.experimental.UtilityClass;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.zone.ZoneRules;

@UtilityClass
public class DateTimeUtil {
    public static final String UNIFORM_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";
    public static final String COMMON_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";
    public static final String UNIFORM_DATE_PATTERN = "yyyy-MM-dd";
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(UNIFORM_DATE_TIME_PATTERN);
    private static final DateTimeFormatter dateFormater = DateTimeFormatter.ofPattern(UNIFORM_DATE_PATTERN);
    public static final DateTimeFormatter COMMON_DATE_FORMATER = DateTimeFormatter.ofPattern(COMMON_DATE_TIME_PATTERN);

    /**
     * 把字符串转为LocalDateTime
     *
     * @param dateTime
     * @return
     */
    public static LocalDateTime stringToLocalDateTime(String dateTime) {
        return LocalDateTime.parse(dateTime, formatter);
    }

    public static LocalDateTime stringToLocalDateTime(String dateTime, DateTimeFormatter commondateFormater) {
        return LocalDateTime.parse(dateTime, commondateFormater);
    }

    /**
     * 把字符串转为LocalDate
     *
     * @param dateTime
     * @return
     */
    public static LocalDate stringToLocalDate(String dateTime) {
        return LocalDate.parse(dateTime, dateFormater);
    }

    /**
     * 把时间转为字符串
     *
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToString(LocalDateTime localDateTime) {
        return localDateTime.format(formatter);
    }

    public static String localDateTimeToStringWithZeroPoint(LocalDateTime localDateTime) {
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MIN).format(formatter);
    }

    /**
     * 把时间转为字符串
     *
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToDateString(LocalDateTime localDateTime) {
        return localDateTime.format(dateFormater);
    }

    public static String localDateToDataString(LocalDate localDate) {
        if (localDate == null) {
            return null;
        }

        return localDate.format(dateFormater);
    }

    /**
     * 获取指定时间当前月的第一天
     *
     * @param localDateTime
     * @return
     */
    public static LocalDateTime getFirstDayOfThisMonth(LocalDateTime localDateTime) {
        return LocalDateTime.of(localDateTime.getYear(), localDateTime.getMonthValue(), 1, 0, 0, 0);
    }

    /**
     * 获取指定时间当前月的最后一天
     *
     * @param localDateTime
     * @return
     */
    public static LocalDateTime getLastDayOfThisMonth(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59)
                .withSecond(59).withNano(999_999_999);
    }

    /**
     * 获取当前月的第一天
     *
     * @return
     */
    public static LocalDateTime getFirstDayOfThisMonth() {
        return getFirstDayOfThisMonth(LocalDateTime.now());
    }

    /**
     * 获取当前月的最后一天
     *
     * @return
     */
    public static LocalDateTime getLastDayOfThisMonth() {
        return getLastDayOfThisMonth(LocalDateTime.now());
    }

    /**
     * 积分系统里面的最大时间，一般用来设置积分等级的过期时间的，不要用错地方，默认认为最大时间为：2099-12-31 23:59:59
     *
     * @return
     */
    public static LocalDateTime getLoyaltyInternalMaxDateTime() {
        return LocalDateTime.of(2099, 12, 31, 23, 59, 59);
    }

    public static LocalDateTime toLocalDateTimeAtDefaultZone(OffsetDateTime offsetDateTime) {
        if (offsetDateTime == null) {
            return null;
        }
        return offsetDateTime.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
    }

    public static OffsetDateTime toOffsetDateTimeAtDefaultZone(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        Clock clock = Clock.systemDefaultZone();
        ZoneId zone = clock.getZone();
        ZoneRules rules = zone.getRules();
        ZoneOffset offset = rules.getOffset(Clock.systemDefaultZone().instant());
        return localDateTime.atOffset(offset);
    }

    public static boolean comparatorOfSameDay(LocalDateTime localDateTime1, LocalDateTime localDateTime2) {
        return localDateTimeToDateString(localDateTime1).equals(localDateTimeToDateString(localDateTime2));
    }

    /**
     * 获取今今年的最后一天
     *
     * @return
     */
    public static LocalDateTime getLastDayOfThisYear() {
        return getLastDayOfYear(LocalDateTime.now());
    }

    /**
     * 获取指定年的最后一天
     *
     * @return
     */
    public static LocalDateTime getLastDayOfYear(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.lastDayOfYear()).withHour(23).withMinute(59)
                .withSecond(59).withNano(999_999_999);
    }

    /**
     * 获取今年的第一天
     *
     * @return
     */
    public static LocalDateTime getFirstDayOfThisYear() {
        return getFirstDayOfYear(LocalDateTime.now());
    }

    /**
     * 获取指定年的第一天
     *
     * @return
     */
    public static LocalDateTime getFirstDayOfYear(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.firstDayOfYear()).withHour(0).withMinute(0).withSecond(0);
    }

    /**
     * 获取今天的开始时间
     *
     * @return
     */
    public static LocalDateTime getBeginTimeOfToday() {
        return getBeginTimeOfDate(LocalDateTime.now());
    }

    /**
     * 获取指定日期的开始时间
     *
     * @return
     */
    public static LocalDateTime getBeginTimeOfDate(LocalDateTime localDateTime) {
        return localDateTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
    }

    /**
     * 获取今天最后的时间
     *
     * @return
     */
    public static LocalDateTime getEndTimeOfToday() {
        return getEndTimeOfDay(LocalDateTime.now());
    }

    /**
     * 获取指定日期最后的时间
     *
     * @return
     */
    public static LocalDateTime getEndTimeOfDay(LocalDateTime localDateTime) {
        return localDateTime.withHour(23).withMinute(59).withSecond(59).withNano(999_999_999);
    }


    /**
     * 获取当前季度的第一天
     */
    public static LocalDateTime getStartDayOfThisQuarter() {
        LocalDate today = LocalDate.now();
        Month month = today.getMonth();
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        return LocalDateTime.of(LocalDate.of(today.getYear(), firstMonthOfQuarter, 1), LocalTime.MIN);
    }

    /**
     * 获取当前季度的第一天
     */
    public static LocalDateTime getStartDayOfQuarter(LocalDateTime localDateTime) {
        LocalDate date = localDateTime.toLocalDate();
        Month month = date.getMonth();
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        return LocalDateTime.of(LocalDate.of(date.getYear(), firstMonthOfQuarter, 1), LocalTime.MIN);
    }

    /**
     * 获取当前季度的最后一天
     */
    public static LocalDateTime getEndDayOfQuarter(LocalDateTime localDateTime) {
        Month month = localDateTime.getMonth();
        Month endMonthOfQuarter = Month.of(month.firstMonthOfQuarter().getValue() + 2);
        return LocalDateTime.of(LocalDate.of(localDateTime.getYear(), endMonthOfQuarter,
                endMonthOfQuarter.length(localDateTime.toLocalDate().isLeapYear())), LocalTime.MAX);
    }

    /**
     * 获取指定季度的第一天
     */
    public static LocalDateTime getStartDayOfGivenQuarter(Integer quarters) {
        quarters = quarters == 0 ? 1 : quarters;
        //获取当前季度的第一天
        LocalDateTime startDayOfThisQuarter = getStartDayOfThisQuarter();
        //根据当前季度后再开始时间往前推多少个3个月
        int minusMonths = 3 * (quarters - 1);
        return startDayOfThisQuarter.minusMonths(minusMonths);
    }

    /**
     * 获取当前季度的最后一天
     */
    public static LocalDateTime getEndDayOfThisQuarter() {
        LocalDate today = LocalDate.now();
        Month month = today.getMonth();
        Month endMonthOfQuarter = Month.of(month.firstMonthOfQuarter().getValue() + 2);
        return LocalDateTime.of(LocalDate.of(today.getYear(), endMonthOfQuarter, endMonthOfQuarter.length(today.isLeapYear())), LocalTime.MAX);
    }

    public static LocalDateTime getEndDayOfFiscalYear(LocalDateTime localDateTime) {
        if (localDateTime.getMonthValue() > 6) {
            return LocalDateTime.of(LocalDate.of(localDateTime.getYear() + 1, 6, 30), LocalTime.MAX);
        }
        return LocalDateTime.of(LocalDate.of(localDateTime.getYear(), 6, 30), LocalTime.MAX);
    }


    public static LocalDateTime getMinDateTime() {
        return LocalDateTime.of(1999, 1, 1, 0, 0, 0);
    }

    public static LocalDateTime getMaxDateTime() {
        return LocalDateTime.of(2099, 12, 31, 23, 59, 59);
    }

}
